#include "RenderModelManager.h"
#include "RenderModelLocal.h"

typedef inf::List<RenderModel*> RenderModelList;

class RenderModelManagerLocal: public RenderModelManager {
public:
    RenderModelManagerLocal();
    ~RenderModelManagerLocal();

    void            Init();
    void            Shutdown();

    RenderModel*    AllocModel();

    RenderModel*    GetModelFromFile( const char* fileName );
    RenderModel*    GenerateStaticModel( genType_t type );
    RenderModel*    FindModel( const char* modelName );
    bool            CheckModel( const char* modelName );

    void            ReloadModels( bool forceAll = false );

protected:
    void            ReleaseAllModels();

    RenderModelList models;
};

RenderModelManagerLocal modelManagerLocal;
RenderModelManager*     modelManager = &modelManagerLocal;

RenderModelManagerLocal::RenderModelManagerLocal()
{

}

RenderModelManagerLocal::~RenderModelManagerLocal()
{

}

void RenderModelManagerLocal::Init()
{
    models.clear();
}

void RenderModelManagerLocal::Shutdown()
{
    ReleaseAllModels();
}

RenderModel* RenderModelManagerLocal::AllocModel()
{
    RenderModel*    model = new RenderModelStatic;
    models.append( model );
    return model;
}

RenderModel* RenderModelManagerLocal::GetModelFromFile( const char* fileName )
{
    RenderModel*    model = NULL;
    inf::Str        str( fileName );
    str.to_lower();

    // check exist...
    if( model = FindModel(fileName) ) {
        return model;
    }

    inf::Str        ext;
    str.extract_file_extension( ext );
    if( ext.cmp("ase") == 0 ) {
        model = new RenderModel_ase;
    }
    model->InitFromFile( fileName );

    models.append( model );
    return model;
}

RenderModel* RenderModelManagerLocal::GenerateStaticModel( genType_t type )
{
    RenderModel*    model = new RenderModelStatic;
    modelSurface_t  modelSurf;

    switch( type ) {
case GT_TRIANGLE:
    {
        modelSurf.geometry = model->AllocSurfaceTriangles(3,3);
        DrawVert*   vert = &modelSurf.geometry->verts[0];
        vert[0].xyz.set(-1.0f,-1.0f,0.0f);
        vert[0].normal.set(0.0f,0.0f,1.0f);
        vert[0].st[0].set(0.0f,0.0f);
        vert[0].SetColor( inf::Color4::pack_Color(inf::Vec4(1.0f,0.0f,0.0f,1.0f)) );
        vert[1].xyz.set(1.0f,-1.0f,0.0f);
        vert[1].normal.set(0.0f,0.0f,1.0f);
        vert[1].st[0].set(1.0f,0.0f);
        vert[1].SetColor( inf::Color4::pack_Color(inf::Vec4(0.0f,1.0f,0.0f,1.0f)) );
        vert[2].xyz.set(0.0f,1.0f,0.0f);
        vert[2].normal.set(0.0f,0.0f,1.0f);
        vert[2].st[0].set(0.0f,1.0f);
        vert[2].SetColor( inf::Color4::pack_Color(inf::Vec4(0.0f,0.0f,1.0f,1.0f)) );

        index_t*    index = &modelSurf.geometry->indexes[0];
        index[0] = 2;
        index[1] = 1;
        index[2] = 0;

        modelSurf.shader = materialManager->GetDefaultMaterial();

        model->AddSurface(modelSurf);
        model->FinishSurfaces();
    } break;
case GT_CUBE:
    {
        modelSurf.geometry = model->AllocSurfaceTriangles(8,36);
        DrawVert*   vert = &modelSurf.geometry->verts[0];
        vert[0].xyz.set(-1.0f,-1.0f,1.0f);
        vert[0].SetColor( inf::Color4::pack_Color(inf::Vec4(1.0f,0.5f,0.0f,1.0f)) );
        vert[1].xyz.set(1.0f,-1.0f,1.0f);
        vert[1].SetColor( inf::Color4::pack_Color(inf::Vec4(0.5f,0.5f,1.0f,1.0f)) );
        vert[2].xyz.set(1.0f,1.0f,1.0f);
        vert[2].SetColor( inf::Color4::pack_Color(inf::Vec4(0.0f,1.0f,1.0f,1.0f)) );
        vert[3].xyz.set(-1.0f,1.0f,1.0f);
        vert[3].SetColor( inf::Color4::pack_Color(inf::Vec4(0.0f,0.5f,1.0f,1.0f)) );

        vert[4].xyz.set(-1.0f,-1.0f,-1.0f);
        vert[4].SetColor( inf::Color4::pack_Color(inf::Vec4(0.0f,0.5f,0.5f,1.0f)) );
        vert[5].xyz.set(1.0f,-1.0f,-1.0f);
        vert[5].SetColor( inf::Color4::pack_Color(inf::Vec4(0.0f,0.25f,0.5f,1.0f)) );
        vert[6].xyz.set(1.0f,1.0f,-1.0f);
        vert[6].SetColor( inf::Color4::pack_Color(inf::Vec4(0.75f,0.5f,0.0f,1.0f)) );
        vert[7].xyz.set(-1.0f,1.0f,-1.0f);
        vert[7].SetColor( inf::Color4::pack_Color(inf::Vec4(1.0f,0.75f,0.0f,1.0f)) );

        index_t*    index = &modelSurf.geometry->indexes[0];
        index[0] = 0; index[1] = 1; index[2] = 2;
        index[3] = 0; index[4] = 2; index[5] = 3;

        index[6] = 1; index[7] = 5; index[8] = 6;
        index[9] = 1; index[10] = 6; index[11] = 2;

        index[12] = 5; index[13] = 4; index[14] = 7;
        index[15] = 5; index[16] = 7; index[17] = 6;

        index[18] = 4; index[19] = 0; index[20] = 3;
        index[21] = 4; index[22] = 3; index[23] = 7;

        index[24] = 4; index[25] = 5; index[26] = 1;
        index[27] = 4; index[28] = 1; index[29] = 0;

        index[30] = 3; index[31] = 2; index[32] = 6;
        index[33] = 3; index[34] = 6; index[35] = 7;

        modelSurf.shader = materialManager->GetDefaultMaterial();

        model->AddSurface(modelSurf);
        model->FinishSurfaces();
    } break;
    }

    models.append( model );
    return model;
}

RenderModel* RenderModelManagerLocal::FindModel( const char* modelName )
{
    return NULL;
}

bool RenderModelManagerLocal::CheckModel( const char* modelName )
{
    return false;
}

void RenderModelManagerLocal::ReloadModels( bool forceAll /*= false */ )
{

}

void RenderModelManagerLocal::ReleaseAllModels()
{
    inf::delete_contents( models, false );
    models.clear();
}

